package cn.jolyoulu.common.web.config;

import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author LuZhouJin
 * @Date 2023/5/25
 * 线程池配置
 */
@Component
public class ThreadPoolConfig {
    //N_CPU：cpu数量
    //U_CPU：目标cpu使用率 0 <= N_CPU <= 1
    //W/C  ：等待时间与计算时间的比率
    //N_THREADS = N_CPU * U_CPU * (1+W/C)
    private final static int N_CPUS = Runtime.getRuntime().availableProcessors();
    private final static int SIZE = (int) (N_CPUS * 0.5 * (1+0.2));

    /**
     * 注入一个线程池
     * @return
     */
    @Bean
    public ExecutorService executorService(){
        return new ThreadPoolExecutor(
            SIZE,                           // 核心线程数
            SIZE * 2,                       // 最大线程数
            60L,                            // 空闲线程存活时间
            TimeUnit.SECONDS,               // 时间单位
            new LinkedBlockingQueue<>(1000),// 任务队列
            new ThreadFactory() {           // 线程工厂（自定义线程名）
                private final AtomicInteger threadNumber = new AtomicInteger(1);
                private final String namePrefix = "custom-executor-";

                @Override
                public Thread newThread(Runnable r) {
                    Thread thread = new Thread(r, namePrefix + threadNumber.getAndIncrement());
                    thread.setDaemon(false); // 非守护线程
                    thread.setPriority(Thread.NORM_PRIORITY); // 正常优先级
                    return thread;
                }
            },
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略（调用者执行）
        );
    }

    /**
     * 配置定时任务线程池
     */
    @Bean
    public TaskScheduler taskScheduler() {
        // 创建线程池任务调度器
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        // 设置线程池大小（根据实际需求调整）
        // 建议根据定时任务数量和系统资源合理设置
        scheduler.setPoolSize(SIZE);
        // 设置线程名称前缀，方便日志追踪
        scheduler.setThreadNamePrefix("scheduled-task-");
        // 线程池关闭时等待所有任务完成
        scheduler.setWaitForTasksToCompleteOnShutdown(true);
        // 等待终止的时间（毫秒）
        scheduler.setAwaitTerminationSeconds(60);
        // 初始化线程池
        scheduler.initialize();
        return scheduler;
    }
}
